//
//  PublishFeedController.swift
//  发布动态界面
//
//  Created by smile on 2019/7/14.
//  Copyright © 2019 ixuea. All rights reserved.
//

import UIKit

//导入TextView提示框架
import KMPlaceholderTextView

//导入键盘关联框架
import KeyboardLayoutGuide

//导入发布订阅框架
import SwiftEventBus

//导入图片选择框架
import PhotoSolution

class PublishFeedController: BaseTitleController {

    /// 输入框
    @IBOutlet weak var tvContent: KMPlaceholderTextView!
    
    
    /// 图片预览列表
    @IBOutlet weak var collectionView: UICollectionView!
    
    /// 当前位置
    @IBOutlet weak var lbLocation: UILabel!
    
    /// 底部的快捷按钮容器
    /// 找到他的目的是
    /// 实现弹出键盘自动上移
    /// 避免被遮挡s
    @IBOutlet weak var svIntoContainer: UIStackView!
    
    /// 字数统计
    @IBOutlet weak var lbCount: UILabel!
    
    /// 动态内容
    var content:String!
    
    /// 列表数据源
    var dataArray:[Any] = []
    
    /// 位置管理器
    var locationManager:AMapLocationManager!
    
    /// 当前位置
    var location:CLLocation?
    
    /// 当前位置geo
    var geo:AMapLocationReGeocode?
    
    override func initViews() {
        super.initViews()
        
        setTitle("发动态")
        
        //设置提示文本
        tvContent.placeholder="人生苦短，我们只做好课！\n千言万语还来不说."
        
        //创建右侧保存按钮
        let saveBarItem = UIBarButtonItem(title: "发布", style: .plain, target: self, action: #selector(onSaveClick))
        
        //添加按钮到右侧导航栏
        navigationItem.rightBarButtonItem=saveBarItem
        
        //添加一个约束
        //目的是让快捷键栏不被软键盘挡住
        svIntoContainer.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor).isActive=true
    }
    
    override func initDatas() {
        super.initDatas()
        
        setData([])
        
        initLocation()
    }
    
    /// 定位
    func initLocation() {
        //创建位置管理器
        locationManager=AMapLocationManager()
        
        //设置定位模式
        //带逆地理信息的一次定位（返回坐标和地址信息）
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        
        //定位超时时间，最低2s，此处设置为2s
        locationManager.locationTimeout=2
        
        //逆地理请求超时时间，最低2s，此处设置为2s
        locationManager.reGeocodeTimeout=2
        
        //开始定位
        startLocation()
    }
    
    /// 开始定位
    /// 虽然模拟器也可以模拟定位
    /// 但比较麻烦
    /// 所以建议大家使用真机
    func startLocation() {
        locationManager.requestLocation(withReGeocode: true) { (location, reGeocode, error) in
            if let error = error {
                //有错误
                
                //判断错误类型
                let error = error as NSError
                
                if error.code == AMapLocationErrorCode.locateFailed.rawValue {
                    //定位错误：此时location和regeocode没有返回值
                    print("PublishFeedController location error:\(error.code),\(error.localizedDescription)")
                }else if error.code == AMapLocationErrorCode.reGeocodeFailed.rawValue
                    || error.code == AMapLocationErrorCode.timeOut.rawValue
                    || error.code == AMapLocationErrorCode.cannotFindHost.rawValue
                    || error.code == AMapLocationErrorCode.badURL.rawValue
                    || error.code == AMapLocationErrorCode.notConnectedToInternet.rawValue
                    || error.code == AMapLocationErrorCode.cannotConnectToHost.rawValue {
                //逆地理错误：在带逆地理的单次定位中，逆地理过程可能发生错误，此时location有返回值，regeocode无返回值
                    print("PublishFeedController re geo error:\(error.code),\(error.localizedDescription)")
                }else {
                    //未知错误
                    print("PublishFeedController location unknown error:\(error.code),\(error.localizedDescription)")
                }
            }else {
                //没有错误
                if let location = location{
                    //经纬度信息
                    print("PublishFeedController location success:\(location)")
                    
                    self.onLocationSucces(location)
                }
                
                if let geo = reGeocode{
                    //GEO信息
                    print("PublishFeedController re geo success:\(reGeocode)")

                    //显示当前位置
                    self.onGeoSuccess(geo)
                }
                
            }
        }
    }
    
    /// 定位成功
    ///
    /// - Parameter location: <#location description#>
    func onLocationSucces(_ location:CLLocation) {
        self.location=location
        
    }
    
    /// 逆地理信息解码成功
    ///
    /// - Parameter geo: <#geo description#>
    func onGeoSuccess(_ geo:AMapLocationReGeocode) {
         self.geo=geo
        
        //显示到界面上
        //这里只显示到市就行了
        //模拟器上data里面的字段可能为空
        lbLocation.text="当前位置：\(geo.province ?? "")-\(geo.city ?? "")"
        
        //真实项目中
        //会添加一个选项
        //然用户选中是否发送地理位置
        //这里就不再实现这么复杂了
    }
    
    override func initListeners() {
        super.initListeners()
        
        //设置文本输入框监听器
        tvContent.delegate=self
    }
    
    /// 保存回调
    @objc func onSaveClick()  {
        print("PublishFeedController onSaveClick")
        
        content = tvContent.text.trim()!
        if content.isEmpty {
            ToastUtil.short("请输入内容.")
            return
        }
        
        if content.length > 140 {
            ToastUtil.short("内容不能超过140字符.")
            return
        }
        
        //获取选择的图片
        let selectedImages = getSelectedImages()
        if selectedImages.count>0 {
            //有图片
            
            //先上传图片
            uploadImage(selectedImages)
        } else {
            //没有图片
            
            //直接发布动态
            saveFeed()
        }

    }
    
    /// 获取选择的图片
    ///
    /// - Returns: <#return value description#>
    func getSelectedImages() -> [UIImage] {
        var result:[UIImage]  = []
        for data in dataArray{
            if data is UIImage {
                //过滤添加图片按钮
                result.append(data as! UIImage)
            }
        }
        
        return result
    }
    
    /// 保存动态
    func saveFeed(_ images:[Dictionary<String,String>]?=nil) {
        
        //保存位置信息
        var longitude:Double?
        var latitude:Double?
        
        if let location = location {
            //有地理位置
            
            //添加经纬度
            //因为后台如果要实现搜索附近的人等功能
            //就需要根据经纬度
            
            //经纬度不会在动态列表中返回
            //所以大家不用担心隐私问题
            let coordinate=location.coordinate
            
            //经度
            longitude=coordinate.longitude
            
            //纬度
            latitude=coordinate.latitude
        }
        
        //没有地理位置
        //我们这里也允许发送动态
        
        var province:String?
        var city:String?
        
        if let geo = geo {
            //geo信息主要用来显示
            //或者直接查询也要保存
            //这里还是只保存省和市
            
            //目的是避免泄漏大家的隐私
            //因为我们这里的动态是所有人都能看
            
            //省
            province=geo.province
            
            //市
            city=geo.city
        }
        
        //没有geo信息
        //我们这里也允许发送动态
        
        Api.shared.createFeed(content: content,province: province,city: city,longitude: longitude,latitude: latitude,images:images).subscribeOnSuccess { (data) in
            //发布通知
            SwiftEventBus.post(ON_FEED_CHANGED)
            
            //关闭界面
            self.navigationController?.popViewController(animated: true)
        }.disposed(by: disposeBag)
    }

    
    /// 选择图片按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onSelectImageClick(_ sender: Any) {
        print("PublishFeedController onSelectImageClick")
        
        selectImage()
    }
    
    /// 选择图片
    func selectImage() {
        //初始化图片选择框架
        let photo = PhotoSolution()
        
        //设置代理
        photo.delegate=self
        
        //设置返回图片的大小
        photo.customization.returnImageSize = .compressed
        
        //显示控制器
        present(photo.getPhotoPicker(maxPhotos: 9), animated: true, completion: nil)
    }
    
    /// 设置数据
    ///
    /// - Parameter _datas: <#_datas description#>
    func setData(_ datas:[UIImage]) {
        dataArray.removeAll()
        
        dataArray=dataArray+datas
        
        if datas.count<9 {
            //没有选择9张图片
            
            //添加一个添加图片按钮
            dataArray.append("AddImage")
        }
        
        collectionView.reloadData()
    }
    
    /// 上传图片
    ///
    /// - Parameter images: <#images description#>
    func uploadImage(_ images:[UIImage]) {
        let oss = IxueaOSSUtil.shared()
        
        var results:[Dictionary<String,String>]=[]
        
        //显示提示框
        ToastUtil.showLoading("上传图片中.")
        
        //在子线程中上传图片
        DispatchQueue.global().async {
            //这里是子线程
            
            //循环图片
            for data in images {
                let putObjectRequest = OSSPutObjectRequest()
                putObjectRequest.bucketName=ALIYUN_OSS_BUCKET_NAME
                
                //上传
                
                //如果没有特殊需求建议不要分目录
                //因为当请求达到一定量级会有性能影响
                //如果一定要分目录
                //不要让目录名前面连续
                //例如时间戳倒过来
                let destinationFileName = "\(UUIDUtil.uuid()).jpg"
                putObjectRequest.objectKey=destinationFileName
                
                //将图片转为data数据
                //压缩为50%
                //值越小质量越差
                //体积越小
                let imageData=data.jpegData(compressionQuality: 0.5)
                
                //直接上传data
                putObjectRequest.uploadingData=imageData!
                
                //上传进度监听
                putObjectRequest.uploadProgress={
                   bytesSent,totalByteSent,totalBytesExpectedToSend in
                
                    //这里没有用到进度所以打印到日志
                    print("PublishFeedController upload image:\(bytesSent),\(totalByteSent),\(totalBytesExpectedToSend))")
                }

                //上传
                let putTask = oss.putObject(putObjectRequest)
                
                //上传完成回调
                putTask.continue({ (task) -> Any? in
                    if task.error == nil{
                        //上传成功了
                        print("PublishFeedController upload image succes")
                    }else {
                        //上传失败了
                        print("PublishFeedController upload image failed:\(task.error)")
                    }
                    
                    return nil
                })
                
                //同步等待
                putTask.waitUntilFinished()
                
                //上传成功
                //将图片保存到数组
                results.append(["uri":destinationFileName])
            }
            
            
            //图片上传完毕
            DispatchQueue.main.async {
                //这里是主线程
                
                //不管成功失败都要隐藏加载提示
                ToastUtil.hideLoading()
                
                //判断是否上传成功
                if images.count == results.count {
                    //所有图片上传成功
                    
                    //发布动态
                    self.saveFeed(results)
                }else {
                    //上传失败
                    ToastUtil.short("图片上传失败，请稍后再试！")
                }
            }
            
        }
    }
}

// MARK: - 文本输入框代理
extension PublishFeedController:UITextViewDelegate {
    
    /// 输入文本回调
    ///
    /// - Parameters:
    ///   - textView: <#textView description#>
    ///   - range: <#range description#>
    ///   - text: <#text description#>
    /// - Returns: <#return value description#>
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        
        let count = tvContent.text.count
        if count >= 140 && !text.isEmpty {
            //超出长度了
            //并且输入的内容不是删除按钮
            
            //不为空是过滤掉删除键
            //因为当按删除键时
            //内容就是空
            return false
        }
        
        return true
    }
    
    /// 文本输入了以后
    ///
    /// - Parameter textView: <#textView description#>
    func textViewDidChange(_ textView: UITextView) {
        let count=tvContent.text.count
        lbCount.text="\(count)/140"
    }
}

// MARK: - 图片选择框架代理
extension PublishFeedController:PhotoSolutionDelegate {
    
    /// 选择了图片
    ///
    /// - Parameter images: <#images description#>
    func returnImages(_ images: [UIImage]) {
        print("PublishFeedController returnImages:\(images.count)")
        
        setData(images)
    }
    
    /// 取消选择了
    func pickerCancel() {
        
    }
}


// MARK: - 列表数据源和代理
extension PublishFeedController:UICollectionViewDataSource,UICollectionViewDelegate{
    
    /// 有多少个
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataArray.count
    }
    
    /// 返回cell
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - indexPath: <#indexPath description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        //获取数据
        let data = dataArray[indexPath.row]
        
        //获取cell
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CELL, for: indexPath) as! SelectImageCell
        
        //设置tag
        cell.tag=indexPath.row
        
        //绑定数据
        cell.bindData(data)
        
        //设置Cell删除图片回调
        cell.onDeleteClick = {
            index in
            self.dataArray.remove(at: index)
            self.collectionView.reloadData()
        }
        
        //返回cell
        return cell
    }
    
    /// cell点击回调
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - indexPath: <#indexPath description#>
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //取出对应位置的数据
        let data=dataArray[indexPath.row]
        
        if data is String {
            //只有添加按钮才能点击
            self.selectImage()
        }
    }
}

// MARK: - UICollectionViewDelegateFlowLayout代理
extension PublishFeedController:UICollectionViewDelegateFlowLayout {
    
    /// 返回cell尺寸
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - collectionViewLayout: <#collectionViewLayout description#>
    ///   - indexPath: <#indexPath description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        //获取到collectionView宽度
        let collectionViewWidth = collectionView.frame.width
        
        //单个cell宽
        let width = (collectionViewWidth-SIZE_LARGE_DIVIDER*2)/3
        
        //返回尺寸
        return CGSize(width: width, height: width)
    }
}
